import * as path from 'path';
import * as fs from 'fs';
import {StringUtil} from "../../utils/StringUtil";
import {FileDownloader} from "./FileDownloader";
import {FileUtil} from "../../utils/FileUtil";

const k1 = "12345678", k2 = "kdjerewd", k3 = "093-1=32", k4 = "abCsd.ed", sin = "dO3eMfJ1Nq";

/**
 * 保利威视的下载器
 */
export class PolyvVideoDownloader {

    /**
     * 构造函数
     * @param downloadParam
     * @param successCallback 构造成功的回调
     */
    constructor(downloadParam, successCallback) {
        let _this = this;
        this.downloadDir = path.join(downloadParam.FileName, "video");
        if (!fs.existsSync(this.downloadDir)) {
            fs.mkdirSync(this.downloadDir);
        }
        this.downloadDir = path.join(this.downloadDir, downloadParam.Vid);
        if (!fs.existsSync(this.downloadDir)) {
            fs.mkdirSync(this.downloadDir);
        }
        this.vid = downloadParam.Vid;

        try {
            //1.下载videoJson
            FileDownloader.syncQueryOneFileContent(StringUtil.format("https://v3.polyv.net/videojson/{0}.js", downloadParam.Vid))
                .then(res => {
                    _this.videoJson = JSON.parse(res);
                    try {
                        //2.从videoJson中获取需要下载的包
                        if (this.videoJson) {
                            let packageUrls = this.videoJson["packageUrl"];
                            _this.videoPkgUrl = _this.findZipFile(packageUrls);
                            console.log('下载地址videoPkgUrl=>>>>', _this.videoPkgUrl)
                            if(_this.videoPkgUrl){
                                //3.获取下载包的大小
                                FileDownloader.getTotalSize(_this.videoPkgUrl, resSize => {
                                    _this.fileDownloader = new FileDownloader(_this.videoPkgUrl, path.join(_this.downloadDir, downloadParam.TaskId + ".zip"));
                                    _this.fileDownloader.totalSize = resSize;
                                    _this.totalSize = resSize;
                                    if (_this.totalSize > 0) {
                                        //4.下载 hlsIndex.m3u8 文件
                                        let hlsIndex = _this.videoJson["hlsIndex"];
                                        FileDownloader.syncDownloadOneFile(hlsIndex, path.join(_this.downloadDir, "hlsIndex.m3u8"), true, function () {
                                            //5.下载hls文件
                                            let hlsUrls = _this.videoJson["hls"];
                                            if (hlsUrls) {
                                                let hlsUrl = _this.findM3u8File(hlsUrls);
                                                if (hlsUrl) {
                                                    let destFile = path.join(_this.downloadDir, hlsUrl.substring(hlsUrl.lastIndexOf('/') + 1, hlsUrl.length));
                                                    const md5 = require('md5-nodejs');
                                                    let curTime = new Date().getTime();
                                                    let sing = md5(StringUtil.format("{0}{1}{2}", sin, _this.vid, curTime));
                                                    sing = StringUtil.format("{0}?ts={1}&sign={2}", hlsUrl, curTime, sing);
                                                    //下载key文件
                                                    FileDownloader.syncDownloadOneFile(sing, destFile, false, function () {
                                                        let destFileContent = fs.readFileSync(destFile, 'utf-8');
                                                        let keyUrl = destFileContent.match(/,URI=\"(\S*)\",IV=/)[1];
                                                        // console.log('keyUrl:'+keyUrl);
                                                        let keyFile = path.join(_this.downloadDir, keyUrl.substring(keyUrl.lastIndexOf('/') + 1, keyUrl.length));
                                                        console.log('keyFile:'+keyFile);
                                                        FileDownloader.syncDownloadOneFile(keyUrl, keyFile, false, function () {
                                                            //加密key文件
                                                            let keyContent = fs.readFileSync(keyFile);
                                                            let crypUtil = require('../../utils/CrypUtil');
                                                            //捕获key文件写入异常
                                                            try {
                                                                FileUtil.writeFile(crypUtil.aesEncrypt(keyContent, k1 + k2 + k3 + k4), keyFile);
                                                                var afterKey = crypUtil.aesEncrypt(keyContent, k1 + k2 + k3 + k4)
                                                                // console.log('读取文件路径返回的buffer数据---------->' + keyContent);
                                                                // console.log(new Buffer(keyContent).toString('base64'));
                                                                // console.log('加密后的key------------>'+ afterKey);
                                                            } catch (error) {
                                                                console.log(error)
                                                            }

                                                            //修改文件内容，去http
                                                            destFileContent = destFileContent.replace(keyUrl, keyUrl.substring(keyUrl.lastIndexOf('/') + 1, keyUrl.length));
                                                            let tempLines = destFileContent.split('\n');
                                                            tempLines.forEach(line => {
                                                                if (line.indexOf("http:") > -1) {
                                                                    destFileContent = destFileContent.replace(line, line.substring(line.lastIndexOf('/') + 1, line.length));
                                                                }
                                                            })
                                                            FileUtil.writeFile(destFileContent, destFile);
                                                            if (successCallback) {
                                                                successCallback();
                                                            }
                                                        }, () => {_this.errorCallback(successCallback);})
                                                    }, () => {_this.errorCallback(successCallback);})
                                                } else {
                                                    _this.errorCallback(successCallback);;
                                                }
                                            } else {
                                                _this.errorCallback(successCallback);
                                            }
                                        }, () => {_this.errorCallback(successCallback);})
                                    } else {
                                        if (successCallback) {
                                            successCallback();
                                        }
                                    }
                                });
                            }else {
                                _this.errorCallback(successCallback);
                            }
                        }
                    } catch (e) {
                        console.log("PolyvVideoDownloader constructor error --> query totalSize");
                        _this.errorCallback(successCallback);
                    }
                }).catch(error => {_this.errorCallback(successCallback);});
        } catch (e) {
            _this.errorCallback(successCallback);
            console.log("PolyvVideoDownloader constructor error --> download videoJson");
        }
    }

    /**
     * 查找应该下载的m3U8文件
     */
    findM3u8File(hlsUrls) {
        //先去找超清的url
        let resultUrl = "";
        hlsUrls.forEach(hlsUrl => {
            if (hlsUrl.indexOf("_3.m3u8")) {//如果有高清的url，就下载高清的
                resultUrl = hlsUrl;
            }
        });
        if (!resultUrl) {
            //再去找高清的url
            hlsUrls.forEach(hlsUrl => {
                if (hlsUrl.indexOf("_2.m3u8")) {//如果有高清的url，就下载高清的
                    resultUrl = hlsUrl;
                }
            })
        }
        if (!resultUrl) {
            //再去找标清的url
            hlsUrls.forEach(hlsUrl => {
                if (hlsUrl.indexOf("_1.m3u8")) {//如果有标清的url，就下载标清的
                    resultUrl = hlsUrl;
                }
            })
        }
        return resultUrl;
    }

    findZipFile(packageUrls) {
        //先去找超清的url
        let resultUrl = "";
        packageUrls.forEach(packageUrl => {
            if (packageUrl.indexOf("_3.zip")) {//如果有高清的url，就下载高清的
                resultUrl = packageUrl;
            }
        });
        if (!resultUrl) {
            //再去找高清的url
            packageUrls.forEach(packageUrl => {
                if (packageUrl.indexOf("_2.zip")) {//如果有高清的url，就下载高清的
                    resultUrl = packageUrl;
                }
            })
        }
        if (!resultUrl) {
            //再去找标清的url
            packageUrls.forEach(packageUrl => {
                if (packageUrl.indexOf("_1.zip")) {//如果有标清的url，就下载标清的
                    resultUrl = packageUrl;
                }
            })
        }
        return resultUrl;
    }

    /**
     * 统一的异常回调处理
     * @param successCallback
     */
    errorCallback(successCallback){
        //总大小置位0，不用再下载
        if(this.fileDownloader){
            this.fileDownloader.totalSize = 0;
        }else {
            this.fileDownloader = new FileDownloader("", "");
            this.fileDownloader.totalSize = 0;
        }
        this.totalSize = 0;
        if (successCallback) {
            successCallback()
        }
    }
}
